home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-05-23 | 16.3 KB | 542 lines | [TEXT/ttxt] |
- { ACCURACY.PAS: 8087 math accuracy test, v 1.7, Oct 1987
- (c) 1987, PC Tech Journal and Ziff Communications Co.
- written by Jim Roberts.
-
- Uncomment the correct constant declarations for your compiler.
- Insert correct version number in `compil' variable,
- name of hardware system & math coprocessor in `machin' variable.
-
- }
- {$MC68020+}
- {$MC68881+}
- {$R+}
- {$U-}
-
- PROGRAM Accuracy2;
-
- USES Memtypes, QuickDraw, OSIntf, ToolIntf, PackIntf, SANE;
-
- TYPE
- accarray = array [1..5] of extended;
-
- CONST
- minerr = 1.0E-17;
- logmin = 17.0;
- n = 10;
- y = 1.0;
- step = 0.2;
- iter = 20;
- itertrig = 5;
- log10e = 0.43429448190325182765;
- pi = 3.14159265358979323846;
- piO2 = 1.57079632679489661923;
- root2 = 1.4142135623730950488;
- root3 = 1.7320508075688772935;
- sqrtO2 = 0.7071067811865475244;
-
- VAR
- i, j, k, l, m, ntest, z: integer;
- a, b, c: array [1..n, 1..n] of extended;
- sum, X: extended;
- xx, zz, quot: extended;
- a0, a1, d0, d1, frac: extended;
- p, p2: extended;
- th, err, logerr, diverr, val, funct: accarray;
- testerr: array [1..10] of extended;
- toterr: extended;
- done: Boolean;
- s: DecStr;
- textWide: integer; { Maximum width of a character }
- textHeight: integer; { Height of a character }
- f: DecForm;
-
- Procedure Pause;
- { Wait for mouse button click. Also clear keyboard events. }
- begin
- while Button do SystemTask;
- while not Button do SystemTask;
- FlushEvents(keyDownMask + autoKeyMask + mDownMask, 0)
- end; { Pause }
-
- Procedure DrawAt(X, y: integer;
- s: Str255);
- { Draw string at this coordinate, similar to an x,y location }
- { on a conventional computer terminal. }
- const
- Xoffset = 5; { Blank pixels in left border }
- Yoffset = 12; { Blank pixels in top border }
- begin
- MoveTo(Xoffset + X * textWide, Yoffset + y * textHeight);
- DrawString(s)
- end; { DrawAt }
-
- Procedure NewFont(fontNumber, pointSize: integer);
- { Select new font and adjust variables for DrawAt }
- begin
- TextFont(fontNumber); { Use new font }
- TextSize(pointSize); { Use new size }
- textHeight := pointSize + 2; { Calc new character height }
- textWide := CharWidth('M') { Calc width of widest char }
- end; { NewFont }
-
- Procedure filla;
- var
- i, j: integer;
- begin
- for i := 1 to n do
- for j := 1 to n do
- if i <> j then
- a[i, j] := y
- else
- a[i, j] := X + y;
- end;
-
- Procedure fillb;
- var
- i, j: integer;
- f, d: extended;
- begin
- f := X + n * y;
- d := 1.0 / (X * f);
- for i := 1 to n do
- for j := 1 to n do
- if i <> j then
- b[i, j] := - y * d
- else
- b[i, j] := ( - y + f) * d;
- end;
-
- Procedure fillc;
- var
- i, j: integer;
- begin
- for i := 1 to n do for j := 1 to n do c[i, j] := 0.0;
- end;
-
- Procedure mult;
- var
- i, j, k: integer;
- begin
- for i := 1 to n do
- for j := 1 to n do
- begin
- sum := 0.0;
- for k := 1 to n do sum := sum + a[i, k] * b[k, j];
- c[i, j] := sum;
- end;
- end;
-
- Procedure sumit;
- var
- i, j: integer;
- begin
- sum := 0.0;
- for i := 1 to n do c[i, i] := c[i, i] - 1.0;
- for i := 1 to n do for j := 1 to n do sum := sum + abs(c[i, j]);
- end;
-
- function osgn(n: integer): extended; {negative if n odd}
- begin
- if n = 2 * (n div 2) then
- osgn := 1.0
- else
- osgn := - 1.0;
- end;
-
- Procedure arith;
- {TEST 1: well-conditioned combinatorial matrix times its inverse.}
- var
- i, k, l, m: integer;
- begin
- zz := 0.30; {factor used to control decrease of condition of matrix}
- for l := 1 to 5 do
- begin
- xx := zz * (3 - l);
- X := exp(xx / log10e); {slowly decreases conditioning}
- filla;
- fillb;
- fillc;
- mult;
- sumit;
- err[l] := sum / sqr(n); {error is average absolute error per element}
- if err[l] > minerr then
- logerr[l] := - ln(err[l]) * log10e
- else
- logerr[l] := logmin;
- testerr[1] := testerr[1] + (logmin - logerr[l]);
- end;
- testerr[1] := testerr[1] / 5.0;
- DrawAt(5, 21, '#1a: 10x10 matrix ');
- f.Style := FixedDecimal;
- f.Digits := 1;
- z := 25;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f, logerr[i], s);
- DrawAt(z, 21, s);
- end;
- f.Digits := 2;
- Num2Str(f, testerr[1], s);
- DrawAt(59, 21, s);
- { infinite product for 1-x: run in reverse to test division }
- sum := 0.0;
- for l := 1 to 5 do
- begin
- xx := (1 - l) / 4.0;
- zz := exp((xx - 2.0) / log10e); {increases number of factors for convergence}
- xx := 1.0 - zz; { zz ≈ .01 => loss of 2 sig figs }
- {The following formula for the number of factors is designed to give
- sufficient accuracy, while avoiding underflow in the powers of xx.
- It gives a more uniform computation from compiler to compiler.}
- m := 12 + l;
- quot := 1.0;
- for k := 1 to m do
- begin
- quot := quot / (1.0 + xx);
- xx := xx * xx;
- end;
- err[l] := abs(1.0 - quot / zz) * 0.01;
- { factor of 0.01 to compensate for cancellation errors }
- if err[l] > minerr then
- diverr[l] := - ln(err[l]) * log10e
- else
- diverr[l] := logmin;
- sum := sum + (logmin - diverr[l]);
- logerr[l] := diverr[l]; {needed for later average}
- end;
- sum := sum / 5.0;
- DrawAt(5, 22, '#1 : infinite product ');
- f.Digits := 1;
- z := 25;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f, diverr[i], s);
- DrawAt(z, 22, s);
- end;
- f.Digits := 2;
- Num2Str(f, sum, s);
- DrawAt(59, 22, s);
- { test continued fraction for tangent against exact values for five angles:
- this is a test of division and subtraction, not of the tangent.}
- th[1] := pi / 12.0;
- th[2] := pi / 6.0;
- th[3] := pi / 4.0;
- th[4] := pi / 3.0;
- th[5] := 5.0 * pi / 12.0;
- val[1] := 2.0 - root3;
- val[2] := 1.0 / root3;
- val[3] := 1.00;
- val[4] := root3;
- val[5] := 2.0 + root3;
- sum := 0.0;
- m := 8; { this number of iterations gives sufficient accuracy }
- for l := 1 to 5 do
- begin
- a0 := 2.0 * m + 1.0;
- p2 := th[l];
- p := sqr(p2);
- d0 := a0 - p / (a0 + 2.0);
- for k := 1 to m do
- begin
- a1 := a0 - 2.0;
- d1 := a1 - p / d0;
- a0 := a1;
- d0 := d1;
- end;
- frac := p2 / d0;
- funct[l] := frac;
- end;
- for l := 1 to 5 do
- begin
- err[l] := abs(1.0 - val[l] / funct[l]);
- if err[l] > minerr then
- diverr[l] := - ln(err[l]) * log10e
- else
- diverr[l] := logmin;
- sum := sum + (logmin - diverr[l]);
- end;
- sum := sum / 5.0;
- DrawAt(5, 23, '#1 : continued fraction ');
- f.Digits := 1;
- z := 25;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f, diverr[i], s);
- DrawAt(z, 23, s);
- end;
- f.Digits := 2;
- Num2Str(f, sum, s);
- DrawAt(59, 23, s);
- for i := 1 to 5 do
- begin
- logerr[i] := 0.5 * (logerr[i] + diverr[i]);
- testerr[2] := testerr[2] + (logmin - logerr[i]);
- end;
- testerr[2] := testerr[2] / 5.0;
- DrawAt(5, 24, '#1b: division average ');
- f.Digits := 1;
- z := 25;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f, logerr[i], s);
- DrawAt(z, 24, s);
- end;
- f.Digits := 2;
- Num2Str(f, testerr[2], s);
- DrawAt(59, 24, s);
- end;
-
- Procedure trig; {TEST 2: first, errors in some sine identities }
- var
- i, j, k, l: integer;
- begin
- for l := 1 to 5 do logerr[l] := 0.0;
- for j := 1 to itertrig do
- begin
- p := j - 1;
- th[1] := pi / 12.0 + p * pi;
- th[2] := pi / 6.0 + p * pi;
- th[3] := pi / 4.0 + p * pi;
- th[4] := pi / 3.0 + p * pi;
- th[5] := 5.0 * pi / 12.0 + p * pi;
- val[1] := osgn(j - 1) * root2 * (root3 - 1.0) * 0.25;
- val[2] := osgn(j - 1) * 0.5;
- val[3] := osgn(j - 1) * sqrtO2;
- val[4] := osgn(j - 1) * 0.5 * root3;
- val[5] := osgn(j - 1) * root2 * (root3 + 1.0) * 0.25;
- for l := 1 to 5 do funct[l] := sin(th[l]);
- for l := 1 to 5 do
- begin
- err[l] := abs(1.0 - val[l] / funct[l]);
- if err[l] > minerr then
- logerr[l] := logerr[l] - ln(err[l]) * log10e
- else
- logerr[l] := logerr[l] + logmin;
- end;
- end;
- for l := 1 to 5 do logerr[l] := logerr[l] / itertrig;
- for l := 1 to 5 do testerr[3] := testerr[3] + (logmin - logerr[l]);
- testerr[3] := testerr[3] / 5.0;
- DrawAt(5, 25, '#2a: sine function ');
- f.Digits := 1;
- z := 25;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f, logerr[i], s);
- DrawAt(z, 25, s);
- end;
- f.Digits := 2;
- Num2Str(f, testerr[3], s);
- DrawAt(59, 25, s);
-
- { compare sin()/cos() with exact values for tan() }
- for l := 1 to 5 do logerr[l] := 0.0;
- for j := 1 to itertrig do
- begin
- p := j - 1;
- th[1] := pi / 12.0 + (j - 1) * pi;
- th[2] := pi / 6.0 + (j - 1) * pi;
- th[3] := pi / 4.0 + (j - 1) * pi;
- th[4] := pi / 3.0 + (j - 1) * pi;
- th[5] := 5.0 * pi / 12.0 + (j - 1) * pi;
- val[1] := 2.0 - root3;
- val[2] := 1.0 / root3;
- val[3] := 1.00;
- val[4] := root3;
- val[5] := 2.0 + root3;
- for l := 1 to 5 do funct[l] := sin(th[l]) / cos(th[l]);
- for l := 1 to 5 do
- begin
- err[l] := abs(1.0 - val[l] / funct[l]);
- if err[l] > minerr then
- logerr[l] := logerr[l] - ln(err[l]) * log10e
- else
- logerr[l] := logerr[l] + logmin;
- end;
- end;
- for l := 1 to 5 do logerr[l] := logerr[l] / itertrig;
- for l := 1 to 5 do testerr[4] := testerr[4] + (logmin - logerr[l]);
- testerr[4] := testerr[4] / 5.0;
- DrawAt(5, 26, '#2b: tangent|sin()/cos()');
- f.Digits := 1;
- z := 25;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f, logerr[i], s);
- DrawAt(z, 26, s);
- end;
- f.Digits := 2;
- Num2Str(f, testerr[4], s);
- DrawAt(59, 26, s);
-
- { compare arctan() with tan() for consistency }
- for l := 1 to 5 do logerr[l] := 0.0;
- for j := 1 to iter do
- begin
- for l := 1 to 5 do th[l] := (5 * j + l - 5) * piO2 / (5 * iter + 1);
- for l := 1 to 5 do val[l] := sin(th[l]) / cos(th[l]);
- for l := 1 to 5 do funct[l] := arctan(val[l]);
- for l := 1 to 5 do
- begin
- err[l] := abs(1.0 - th[l] / funct[l]);
- if err[l] > minerr then
- logerr[l] := logerr[l] - ln(err[l]) * log10e
- else
- logerr[l] := logerr[l] + logmin;
- end;
- end;
- for l := 1 to 5 do logerr[l] := logerr[l] / iter;
- for l := 1 to 5 do testerr[5] := testerr[5] + (logmin - logerr[l]);
- testerr[5] := testerr[5] / 5.0;
- DrawAt(5, 27, '#2c: arctan function ');
- f.Digits := 1;
- z := 25;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f, logerr[i], s);
- DrawAt(z, 27, s);
- end;
- f.Digits := 2;
- Num2Str(f, testerr[5], s);
- DrawAt(59, 27, s);
- end;
-
- Procedure transc; {TEST 3: ln() and exp() for consistency}
- var
- i, j, l: integer;
- begin
- for l := 1 to 5 do logerr[l] := 0.0;
- for j := 1 to iter do
- begin
- for l := 1 to 5 do th[l] := (5 * j + l - 5) * step;
- for l := 1 to 5 do val[l] := exp(th[l]);
- for l := 1 to 5 do funct[l] := ln(val[l]);
- for l := 1 to 5 do
- begin
- err[l] := abs(1.0 - th[l] / funct[l]);
- if err[l] > minerr then
- logerr[l] := logerr[l] - ln(err[l]) * log10e
- else
- logerr[l] := logerr[l] + logmin;
- end;
- end;
- for l := 1 to 5 do logerr[l] := logerr[l] / iter;
- for l := 1 to 5 do testerr[6] := testerr[6] + (logmin - logerr[l]);
- testerr[6] := testerr[6] / 5.0;
- DrawAt(5, 28, '#3a: ln() & exp() ');
- f.Digits := 1;
- z := 25;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f, logerr[i], s);
- DrawAt(z, 28, s);
- end;
- f.Digits := 2;
- Num2Str(f, testerr[6], s);
- DrawAt(59, 28, s);
- end;
-
- Procedure roots; { sqrt() and sqr() identities }
- var
- i, j, l: integer;
- begin
- for l := 1 to 5 do logerr[l] := 0.0;
- for j := 1 to iter do
- begin
- for l := 1 to 5 do th[l] := (5 * j + l - 5) * step;
- for l := 1 to 5 do val[l] := sqrt(th[l]);
- for l := 1 to 5 do funct[l] := sqr(val[l]);
- for l := 1 to 5 do
- begin
- err[l] := abs(1.0 - th[l] / funct[l]);
- if err[l] > minerr then
- logerr[l] := logerr[l] - ln(err[l]) * log10e
- else
- logerr[l] := logerr[l] + logmin;
- end;
- end;
- for l := 1 to 5 do logerr[l] := logerr[l] / iter;
- for l := 1 to 5 do testerr[7] := testerr[7] + (logmin - logerr[l]);
- testerr[7] := testerr[7] / 5.0;
- DrawAt(5, 29, '#3b: sqrt() & sqr() ');
- f.Digits := 1;
- z := 25;
- for i := 1 to 5 do
- begin
- z := z + 5;
- Num2Str(f, logerr[i], s);
- DrawAt(z, 29, s);
- end;
- f.Digits := 2;
- Num2Str(f, testerr[7], s);
- DrawAt(59, 29, s);
- end;
-
- Procedure Initialize;
- { Perform one-time setup work. }
- var
- r: Rect;
- MyNewWindow: WindowPtr;
- begin
- InitGraf(@thePort); { initialize QuickDraw }
- InitFonts; { " Font Manager }
- InitWindows; { " Window Manager }
- InitCursor; { make cursor an arrow }
- done := False;
- SetRect(r, 30, 60, 600, 400);
- MyNewWindow := NewWindow(nil, r, 'Accuracy Tester', True, documentProc, Pointer( - 1), True,
- 0);
- MyNewWindow^.txFace := [bold];
- MyNewWindow^.txFont := SystemFont;
- windowPeek(MyNewWindow)^.refCon := Longint(NewString('Contents of window 1'));
- end;
-
- Procedure Header;
- begin
- NewFont(monaco, 9);
- TextFace([]);
- DrawAt(5, 6, 'ACCURACY: extended tester: MPW Pascal: Macintosh II');
- DrawAt(5, 7, ' V 1.7 (c) 1987, PC Tech Journal and Ziff Communications Co.');
- DrawAt(5, 8, ' written by Jim Roberts.');
- DrawAt(5,9,' Modified for Macintosh & Turbo Pascal by Morry Hodges, CIS 74766,3426');
- DrawAt(5, 10, 'Test 1 checks multiplication and addition, then division and subtraction.');
- DrawAt(5, 11,
- 'Test 2 measures the accuracy of the Turbo trig functions (there is no tan()).');
- DrawAt(5, 12, 'Test 3 finds the truncation error in some exponential and sqrt identities.');
- DrawAt(5, 13, 'ACCURACY is the rounded negative log of error. Program may exit abnormally.');
- DrawAt(5, 14, 'NOTE: an increase of 1 in the rating means a factor of TEN less accurate.');
- DrawAt(5, 16, 'Interpretation <0.0 - 0.5 => Excellent 1.0 - 1.5 => Fair');
- DrawAt(5, 17, ' of RATING: 0.5 - 1.0 => Good 1.5 < => Poor');
- DrawAt(5, 18, '');
- DrawAt(5, 19, ' TESTS ACCURACY RATING ');
- end;
-
- begin { program ACCURACY begins here }
- repeat
- Initialize;
- Header;
- for i := 1 to 10 do testerr[i] := 0.0;
- arith;
- trig;
- transc;
- roots;
- ntest := 7;
- toterr := 0.0;
- for i := 1 to ntest do toterr := toterr + testerr[i];
- toterr := toterr / ntest;
- DrawAt(5, 31, 'Overall rating:');
- Num2Str(f, toterr, s);
- DrawAt(23, 31, s);
- DrawAt(5, 33, 'Click mouse to finish');
- Pause;
- until Button;
- end.
-